import React, { useMemo, useRef, useState } from 'react';

import cs from 'classnames';
import type { EChartsType } from 'echarts';

import { px2rem } from '@/utils';

import type { ChartProps } from '../index';
import styles from './index.module.scss';

export type DataType = {
  name: string;
  value: number;
};

export type WithCustomLegendComponentProps = {
  /** 数据 */
  data: DataType[];
  wrapClassName?: string;
  legendClassName?: string;
  legend?: (
    data: DataType & {
      index: number;
      selected: boolean;
      color: string;
      colorNode: React.ReactElement;
      percent: number;
    }
  ) => React.ReactElement;
};

const withCustomLegend = () => {
  return <P extends ChartProps>(Component: React.ComponentType<P>) => {
    return ({
      data: propsData,
      wrapClassName: propsWrapClassName,
      className: propsClassName,
      legendClassName: propsLegendClassName,
      legend: propsLegend,
      onChartReady: propsOnChartReady,
      ...props
    }: P & WithCustomLegendComponentProps) => {
      const instance = useRef<EChartsType>();
      const [colors, setColors] = useState<string[]>([]);
      const [selectedLegends, setSelectedLegends] = useState<string[]>(
        propsData.map((v) => v.name)
      );
      const total = useMemo(() => {
        return propsData.reduce<number>((acc, cur) => acc + cur.value, 0);
      }, [propsData]);

      const onChartReady: ChartProps['onChartReady'] = (e: echarts.ECharts) => {
        instance.current = e;
        propsOnChartReady?.(e);
        setColors(e.getOption().color as string[]);

        e.on('legendselectchanged', (event) => {
          const selected = (event as Record<string, any>).selected;
          const list: string[] = [];

          for (const key in selected) {
            if (selected[key] === true) {
              list.push(key);
            }
          }

          setSelectedLegends(list);
        });
      };

      const handleLegendClick = (item: DataType) => {
        instance.current?.dispatchAction({
          type: 'legendToggleSelect',
          name: item.name
        });
      };

      return (
        <div className={cs(styles['chart-wrap'], propsWrapClassName)}>
          <Component
            className={cs(styles['chart'], propsClassName)}
            onChartReady={onChartReady}
            data={propsData}
            {...(props as unknown as P)}
          />

          {propsLegend ? (
            <div className={cs(styles['legend'], propsLegendClassName)}>
              {propsData.map((item, index) => {
                const selected = selectedLegends.includes(item.name);
                const percent = (item.value / total) * 100 || 0;
                const color = selected ? colors[index] : '#ccc';

                const colorNode = (
                  <i
                    style={{
                      display: 'inline-block',
                      width: px2rem(6),
                      height: px2rem(6),
                      borderRadius: px2rem(1),
                      background: color
                    }}
                  />
                );

                const legend = propsLegend({
                  ...item,
                  index,
                  selected,
                  color,
                  colorNode,
                  percent
                });

                return React.cloneElement(legend, {
                  key: item.name,
                  onClick: handleLegendClick.bind({}, item),
                  onMouseEnter: () => {
                    if (!instance.current) {
                      return;
                    }

                    instance.current.dispatchAction({
                      type: 'downplay',
                      seriesIndex: 0
                    });

                    instance.current.dispatchAction({
                      type: 'highlight',
                      seriesIndex: 0,
                      dataIndex: index
                    });

                    instance.current.dispatchAction({
                      type: 'showTip',
                      seriesIndex: 0,
                      dataIndex: index
                    });
                  }
                });
              })}
            </div>
          ) : null}
        </div>
      );
    };
  };
};

export { withCustomLegend };
